/*
Copyright 2020 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1alpha4

import (
	"errors"
	"fmt"
	"maps"
	"reflect"
	"slices"
	"sort"
	"unsafe"

	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	apimachineryconversion "k8s.io/apimachinery/pkg/conversion"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/utils/ptr"
	"sigs.k8s.io/controller-runtime/pkg/conversion"

	clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1"
	clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
	utilconversion "sigs.k8s.io/cluster-api/util/conversion"
)

var apiVersionGetter = func(_ schema.GroupKind) (string, error) {
	return "", errors.New("apiVersionGetter not set")
}

func SetAPIVersionGetter(f func(gk schema.GroupKind) (string, error)) {
	apiVersionGetter = f
}

func (src *Cluster) ConvertTo(dstRaw conversion.Hub) error {
	dst := dstRaw.(*clusterv1.Cluster)

	if err := Convert_v1alpha4_Cluster_To_v1beta2_Cluster(src, dst, nil); err != nil {
		return err
	}

	if src.Spec.InfrastructureRef != nil {
		infraRef, err := convertToContractVersionedObjectReference(src.Spec.InfrastructureRef)
		if err != nil {
			return err
		}
		dst.Spec.InfrastructureRef = infraRef
	}

	if src.Spec.ControlPlaneRef != nil {
		controlPlaneRef, err := convertToContractVersionedObjectReference(src.Spec.ControlPlaneRef)
		if err != nil {
			return err
		}
		dst.Spec.ControlPlaneRef = controlPlaneRef
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1alpha4 conditions should not be automatically be converted into v1beta2 conditions.
	dst.Status.Conditions = nil

	// Move legacy conditions (v1alpha4), failureReason and failureMessage to the deprecated field.
	if src.Status.Conditions != nil || src.Status.FailureReason != nil || src.Status.FailureMessage != nil {
		dst.Status.Deprecated = &clusterv1.ClusterDeprecatedStatus{}
		dst.Status.Deprecated.V1Beta1 = &clusterv1.ClusterV1Beta1DeprecatedStatus{}
		if src.Status.Conditions != nil {
			Convert_v1alpha4_Conditions_To_v1beta2_Deprecated_V1Beta1_Conditions(&src.Status.Conditions, &dst.Status.Deprecated.V1Beta1.Conditions)
		}
		dst.Status.Deprecated.V1Beta1.FailureReason = src.Status.FailureReason
		dst.Status.Deprecated.V1Beta1.FailureMessage = src.Status.FailureMessage
	}

	// Move ControlPlaneReady and InfrastructureReady to initialization is implemented in ConvertTo.

	// Manually restore data.
	restored := &clusterv1.Cluster{}
	ok, err := utilconversion.UnmarshalData(src, restored)
	if err != nil {
		return err
	}

	// Recover intent for bool values converted to *bool.
	clusterv1.Convert_bool_To_Pointer_bool(src.Spec.Paused, ok, restored.Spec.Paused, &dst.Spec.Paused)

	initialization := clusterv1.ClusterInitializationStatus{}
	restoredControlPlaneInitialized := restored.Status.Initialization.ControlPlaneInitialized
	restoredInfrastructureProvisioned := restored.Status.Initialization.InfrastructureProvisioned
	clusterv1.Convert_bool_To_Pointer_bool(src.Status.ControlPlaneReady, ok, restoredControlPlaneInitialized, &initialization.ControlPlaneInitialized)
	clusterv1.Convert_bool_To_Pointer_bool(src.Status.InfrastructureReady, ok, restoredInfrastructureProvisioned, &initialization.InfrastructureProvisioned)
	if !reflect.DeepEqual(initialization, clusterv1.ClusterInitializationStatus{}) {
		dst.Status.Initialization = initialization
	}

	for i, fd := range dst.Status.FailureDomains {
		srcFD, ok := src.Status.FailureDomains[fd.Name]
		if !ok {
			return fmt.Errorf("failure domain %q not found in source data", fd.Name)
		}
		var restoredFDControlPlane *bool
		for _, restoredFD := range restored.Status.FailureDomains {
			if restoredFD.Name == fd.Name {
				restoredFDControlPlane = restoredFD.ControlPlane
				break
			}
		}
		clusterv1.Convert_bool_To_Pointer_bool(srcFD.ControlPlane, ok, restoredFDControlPlane, &fd.ControlPlane)
		dst.Status.FailureDomains[i] = fd
	}

	// Recover other values
	if ok {
		dst.Spec.AvailabilityGates = restored.Spec.AvailabilityGates
		dst.Spec.Topology.ClassRef.Namespace = restored.Spec.Topology.ClassRef.Namespace
		dst.Spec.Topology.Variables = restored.Spec.Topology.Variables
		dst.Spec.Topology.ControlPlane.Variables = restored.Spec.Topology.ControlPlane.Variables

		dst.Spec.Topology.ControlPlane.HealthCheck = restored.Spec.Topology.ControlPlane.HealthCheck

		if restored.Spec.Topology.ControlPlane.Deletion.NodeDrainTimeoutSeconds != nil {
			dst.Spec.Topology.ControlPlane.Deletion.NodeDrainTimeoutSeconds = restored.Spec.Topology.ControlPlane.Deletion.NodeDrainTimeoutSeconds
		}

		if restored.Spec.Topology.ControlPlane.Deletion.NodeVolumeDetachTimeoutSeconds != nil {
			dst.Spec.Topology.ControlPlane.Deletion.NodeVolumeDetachTimeoutSeconds = restored.Spec.Topology.ControlPlane.Deletion.NodeVolumeDetachTimeoutSeconds
		}

		if restored.Spec.Topology.ControlPlane.Deletion.NodeDeletionTimeoutSeconds != nil {
			dst.Spec.Topology.ControlPlane.Deletion.NodeDeletionTimeoutSeconds = restored.Spec.Topology.ControlPlane.Deletion.NodeDeletionTimeoutSeconds
		}
		dst.Spec.Topology.ControlPlane.ReadinessGates = restored.Spec.Topology.ControlPlane.ReadinessGates

		for i := range restored.Spec.Topology.Workers.MachineDeployments {
			dst.Spec.Topology.Workers.MachineDeployments[i].FailureDomain = restored.Spec.Topology.Workers.MachineDeployments[i].FailureDomain
			dst.Spec.Topology.Workers.MachineDeployments[i].Variables = restored.Spec.Topology.Workers.MachineDeployments[i].Variables
			dst.Spec.Topology.Workers.MachineDeployments[i].ReadinessGates = restored.Spec.Topology.Workers.MachineDeployments[i].ReadinessGates
			dst.Spec.Topology.Workers.MachineDeployments[i].Deletion.Order = restored.Spec.Topology.Workers.MachineDeployments[i].Deletion.Order
			dst.Spec.Topology.Workers.MachineDeployments[i].Deletion.NodeDrainTimeoutSeconds = restored.Spec.Topology.Workers.MachineDeployments[i].Deletion.NodeDrainTimeoutSeconds
			dst.Spec.Topology.Workers.MachineDeployments[i].Deletion.NodeVolumeDetachTimeoutSeconds = restored.Spec.Topology.Workers.MachineDeployments[i].Deletion.NodeVolumeDetachTimeoutSeconds
			dst.Spec.Topology.Workers.MachineDeployments[i].Deletion.NodeDeletionTimeoutSeconds = restored.Spec.Topology.Workers.MachineDeployments[i].Deletion.NodeDeletionTimeoutSeconds
			dst.Spec.Topology.Workers.MachineDeployments[i].MinReadySeconds = restored.Spec.Topology.Workers.MachineDeployments[i].MinReadySeconds
			dst.Spec.Topology.Workers.MachineDeployments[i].Rollout.Strategy = restored.Spec.Topology.Workers.MachineDeployments[i].Rollout.Strategy
			dst.Spec.Topology.Workers.MachineDeployments[i].HealthCheck = restored.Spec.Topology.Workers.MachineDeployments[i].HealthCheck
		}

		dst.Spec.Topology.Workers.MachinePools = restored.Spec.Topology.Workers.MachinePools

		dst.Status.Conditions = restored.Status.Conditions
		dst.Status.ControlPlane = restored.Status.ControlPlane
		dst.Status.Workers = restored.Status.Workers
	}

	return nil
}

func (dst *Cluster) ConvertFrom(srcRaw conversion.Hub) error {
	src := srcRaw.(*clusterv1.Cluster)

	if err := Convert_v1beta2_Cluster_To_v1alpha4_Cluster(src, dst, nil); err != nil {
		return err
	}

	if src.Spec.InfrastructureRef.IsDefined() {
		infraRef, err := convertToObjectReference(src.Spec.InfrastructureRef, src.Namespace)
		if err != nil {
			return err
		}
		dst.Spec.InfrastructureRef = infraRef
	}

	if src.Spec.ControlPlaneRef.IsDefined() {
		controlPlaneRef, err := convertToObjectReference(src.Spec.ControlPlaneRef, src.Namespace)
		if err != nil {
			return err
		}
		dst.Spec.ControlPlaneRef = controlPlaneRef
	}

	if dst.Spec.ClusterNetwork != nil && dst.Spec.ClusterNetwork.APIServerPort != nil &&
		*dst.Spec.ClusterNetwork.APIServerPort == 0 {
		dst.Spec.ClusterNetwork.APIServerPort = nil
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1beta2 conditions should not be automatically be converted into legacy conditions (v1alpha4).
	dst.Status.Conditions = nil

	// Retrieve legacy conditions (v1alpha4), failureReason and failureMessage from the deprecated field.
	if src.Status.Deprecated != nil {
		if src.Status.Deprecated.V1Beta1 != nil {
			if src.Status.Deprecated.V1Beta1.Conditions != nil {
				Convert_v1beta2_Deprecated_V1Beta1_Conditions_To_v1alpha4_Conditions(&src.Status.Deprecated.V1Beta1.Conditions, &dst.Status.Conditions)
			}
			dst.Status.FailureReason = src.Status.Deprecated.V1Beta1.FailureReason
			dst.Status.FailureMessage = src.Status.Deprecated.V1Beta1.FailureMessage
		}
	}

	// Move initialization to old fields
	dst.Status.ControlPlaneReady = ptr.Deref(src.Status.Initialization.ControlPlaneInitialized, false)
	dst.Status.InfrastructureReady = ptr.Deref(src.Status.Initialization.InfrastructureProvisioned, false)

	// Preserve Hub data on down-conversion except for metadata
	if err := utilconversion.MarshalData(src, dst); err != nil {
		return err
	}

	return nil
}

func (src *ClusterClass) ConvertTo(dstRaw conversion.Hub) error {
	dst := dstRaw.(*clusterv1.ClusterClass)

	if err := Convert_v1alpha4_ClusterClass_To_v1beta2_ClusterClass(src, dst, nil); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1alpha4 conditions should not be automatically be converted into v1beta2 conditions.
	dst.Status.Conditions = nil

	// Manually restore data.
	restored := &clusterv1.ClusterClass{}
	if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
		return err
	}

	dst.Spec.Patches = restored.Spec.Patches
	dst.Spec.Variables = restored.Spec.Variables
	dst.Spec.AvailabilityGates = restored.Spec.AvailabilityGates
	dst.Spec.ControlPlane.HealthCheck = restored.Spec.ControlPlane.HealthCheck
	dst.Spec.ControlPlane.ReadinessGates = restored.Spec.ControlPlane.ReadinessGates
	dst.Spec.ControlPlane.Naming = restored.Spec.ControlPlane.Naming
	dst.Spec.Infrastructure.Naming = restored.Spec.Infrastructure.Naming
	dst.Spec.ControlPlane.Deletion.NodeDrainTimeoutSeconds = restored.Spec.ControlPlane.Deletion.NodeDrainTimeoutSeconds
	dst.Spec.ControlPlane.Deletion.NodeVolumeDetachTimeoutSeconds = restored.Spec.ControlPlane.Deletion.NodeVolumeDetachTimeoutSeconds
	dst.Spec.ControlPlane.Deletion.NodeDeletionTimeoutSeconds = restored.Spec.ControlPlane.Deletion.NodeDeletionTimeoutSeconds
	dst.Spec.Workers.MachinePools = restored.Spec.Workers.MachinePools
	dst.Spec.KubernetesVersions = restored.Spec.KubernetesVersions

	for i := range restored.Spec.Workers.MachineDeployments {
		dst.Spec.Workers.MachineDeployments[i].HealthCheck = restored.Spec.Workers.MachineDeployments[i].HealthCheck
		dst.Spec.Workers.MachineDeployments[i].ReadinessGates = restored.Spec.Workers.MachineDeployments[i].ReadinessGates
		dst.Spec.Workers.MachineDeployments[i].FailureDomain = restored.Spec.Workers.MachineDeployments[i].FailureDomain
		dst.Spec.Workers.MachineDeployments[i].Naming = restored.Spec.Workers.MachineDeployments[i].Naming
		dst.Spec.Workers.MachineDeployments[i].Deletion.Order = restored.Spec.Workers.MachineDeployments[i].Deletion.Order
		dst.Spec.Workers.MachineDeployments[i].Deletion.NodeDrainTimeoutSeconds = restored.Spec.Workers.MachineDeployments[i].Deletion.NodeDrainTimeoutSeconds
		dst.Spec.Workers.MachineDeployments[i].Deletion.NodeVolumeDetachTimeoutSeconds = restored.Spec.Workers.MachineDeployments[i].Deletion.NodeVolumeDetachTimeoutSeconds
		dst.Spec.Workers.MachineDeployments[i].Deletion.NodeDeletionTimeoutSeconds = restored.Spec.Workers.MachineDeployments[i].Deletion.NodeDeletionTimeoutSeconds
		dst.Spec.Workers.MachineDeployments[i].MinReadySeconds = restored.Spec.Workers.MachineDeployments[i].MinReadySeconds
		dst.Spec.Workers.MachineDeployments[i].Rollout.Strategy = restored.Spec.Workers.MachineDeployments[i].Rollout.Strategy
	}
	dst.Status = restored.Status
	dst.Spec.Upgrade.External.GenerateUpgradePlanExtension = restored.Spec.Upgrade.External.GenerateUpgradePlanExtension

	return nil
}

func (dst *ClusterClass) ConvertFrom(srcRaw conversion.Hub) error {
	src := srcRaw.(*clusterv1.ClusterClass)

	if err := Convert_v1beta2_ClusterClass_To_v1alpha4_ClusterClass(src, dst, nil); err != nil {
		return err
	}

	// Preserve Hub data on down-conversion except for metadata
	if err := utilconversion.MarshalData(src, dst); err != nil {
		return err
	}

	return nil
}

func (src *Machine) ConvertTo(dstRaw conversion.Hub) error {
	dst := dstRaw.(*clusterv1.Machine)

	if err := Convert_v1alpha4_Machine_To_v1beta2_Machine(src, dst, nil); err != nil {
		return err
	}

	if err := convertMachineSpecToContractVersionedObjectReference(&src.Spec, &dst.Spec); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1alpha4 conditions should not be automatically be converted into v1beta2 conditions.
	dst.Status.Conditions = nil

	// Move legacy conditions (v1alpha4), failureReason and failureMessage to the deprecated field.
	if src.Status.Conditions != nil || src.Status.FailureReason != nil || src.Status.FailureMessage != nil {
		dst.Status.Deprecated = &clusterv1.MachineDeprecatedStatus{}
		dst.Status.Deprecated.V1Beta1 = &clusterv1.MachineV1Beta1DeprecatedStatus{}
		if src.Status.Conditions != nil {
			Convert_v1alpha4_Conditions_To_v1beta2_Deprecated_V1Beta1_Conditions(&src.Status.Conditions, &dst.Status.Deprecated.V1Beta1.Conditions)
		}
		dst.Status.Deprecated.V1Beta1.FailureReason = src.Status.FailureReason
		dst.Status.Deprecated.V1Beta1.FailureMessage = src.Status.FailureMessage
	}

	// Manually restore data.
	restored := &clusterv1.Machine{}
	ok, err := utilconversion.UnmarshalData(src, restored)
	if err != nil {
		return err
	}

	// Recover intent for bool values converted to *bool.
	initialization := clusterv1.MachineInitializationStatus{}
	restoredBootstrapDataSecretCreated := restored.Status.Initialization.BootstrapDataSecretCreated
	restoredInfrastructureProvisioned := restored.Status.Initialization.InfrastructureProvisioned
	clusterv1.Convert_bool_To_Pointer_bool(src.Status.BootstrapReady, ok, restoredBootstrapDataSecretCreated, &initialization.BootstrapDataSecretCreated)
	clusterv1.Convert_bool_To_Pointer_bool(src.Status.InfrastructureReady, ok, restoredInfrastructureProvisioned, &initialization.InfrastructureProvisioned)
	if !reflect.DeepEqual(initialization, clusterv1.MachineInitializationStatus{}) {
		dst.Status.Initialization = initialization
	}

	// Recover other values
	if ok {
		dst.Spec.MinReadySeconds = restored.Spec.MinReadySeconds
		dst.Spec.ReadinessGates = restored.Spec.ReadinessGates
		dst.Spec.Deletion.NodeDeletionTimeoutSeconds = restored.Spec.Deletion.NodeDeletionTimeoutSeconds
		dst.Status.CertificatesExpiryDate = restored.Status.CertificatesExpiryDate
		dst.Spec.Deletion.NodeVolumeDetachTimeoutSeconds = restored.Spec.Deletion.NodeVolumeDetachTimeoutSeconds
		dst.Spec.Taints = restored.Spec.Taints
		dst.Status.Deletion = restored.Status.Deletion
		dst.Status.Conditions = restored.Status.Conditions
	}

	return nil
}

func (dst *Machine) ConvertFrom(srcRaw conversion.Hub) error {
	src := srcRaw.(*clusterv1.Machine)

	if err := Convert_v1beta2_Machine_To_v1alpha4_Machine(src, dst, nil); err != nil {
		return err
	}

	if err := convertMachineSpecToObjectReference(&src.Spec, &dst.Spec, src.Namespace); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1beta2 conditions should not be automatically be converted into legacy conditions (v1alpha4).
	dst.Status.Conditions = nil

	// Retrieve legacy conditions (v1alpha4), failureReason and failureMessage from the deprecated field.
	if src.Status.Deprecated != nil {
		if src.Status.Deprecated.V1Beta1 != nil {
			if src.Status.Deprecated.V1Beta1.Conditions != nil {
				Convert_v1beta2_Deprecated_V1Beta1_Conditions_To_v1alpha4_Conditions(&src.Status.Deprecated.V1Beta1.Conditions, &dst.Status.Conditions)
			}
			dst.Status.FailureReason = src.Status.Deprecated.V1Beta1.FailureReason
			dst.Status.FailureMessage = src.Status.Deprecated.V1Beta1.FailureMessage
		}
	}

	// Move initialization to old fields
	dst.Status.BootstrapReady = ptr.Deref(src.Status.Initialization.BootstrapDataSecretCreated, false)
	dst.Status.InfrastructureReady = ptr.Deref(src.Status.Initialization.InfrastructureProvisioned, false)

	dropEmptyStringsMachineSpec(&dst.Spec)

	// Preserve Hub data on down-conversion except for metadata
	if err := utilconversion.MarshalData(src, dst); err != nil {
		return err
	}

	return nil
}

func (src *MachineSet) ConvertTo(dstRaw conversion.Hub) error {
	dst := dstRaw.(*clusterv1.MachineSet)

	if err := Convert_v1alpha4_MachineSet_To_v1beta2_MachineSet(src, dst, nil); err != nil {
		return err
	}

	if err := convertMachineSpecToContractVersionedObjectReference(&src.Spec.Template.Spec, &dst.Spec.Template.Spec); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1alpha4 conditions should not be automatically be converted into v1beta2 conditions.
	dst.Status.Conditions = nil

	// Move legacy conditions (v1alpha4), failureReason, failureMessage and replica counters to the deprecated field.
	dst.Status.Deprecated = &clusterv1.MachineSetDeprecatedStatus{}
	dst.Status.Deprecated.V1Beta1 = &clusterv1.MachineSetV1Beta1DeprecatedStatus{}
	if src.Status.Conditions != nil {
		Convert_v1alpha4_Conditions_To_v1beta2_Deprecated_V1Beta1_Conditions(&src.Status.Conditions, &dst.Status.Deprecated.V1Beta1.Conditions)
	}
	dst.Status.Deprecated.V1Beta1.FailureReason = src.Status.FailureReason
	dst.Status.Deprecated.V1Beta1.FailureMessage = src.Status.FailureMessage
	dst.Status.Deprecated.V1Beta1.ReadyReplicas = src.Status.ReadyReplicas
	dst.Status.Deprecated.V1Beta1.AvailableReplicas = src.Status.AvailableReplicas
	dst.Status.Deprecated.V1Beta1.FullyLabeledReplicas = src.Status.FullyLabeledReplicas

	if src.Spec.MinReadySeconds == 0 {
		dst.Spec.Template.Spec.MinReadySeconds = nil
	} else {
		dst.Spec.Template.Spec.MinReadySeconds = &src.Spec.MinReadySeconds
	}

	// Manually restore data.
	restored := &clusterv1.MachineSet{}
	if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
		return err
	}

	dst.Spec.Template.Spec.ReadinessGates = restored.Spec.Template.Spec.ReadinessGates
	dst.Spec.Template.Spec.Deletion.NodeDeletionTimeoutSeconds = restored.Spec.Template.Spec.Deletion.NodeDeletionTimeoutSeconds
	dst.Spec.Template.Spec.Deletion.NodeVolumeDetachTimeoutSeconds = restored.Spec.Template.Spec.Deletion.NodeVolumeDetachTimeoutSeconds
	dst.Spec.Template.Spec.Taints = restored.Spec.Template.Spec.Taints
	dst.Status.Conditions = restored.Status.Conditions
	dst.Status.AvailableReplicas = restored.Status.AvailableReplicas
	dst.Status.ReadyReplicas = restored.Status.ReadyReplicas
	dst.Status.UpToDateReplicas = restored.Status.UpToDateReplicas
	dst.Spec.MachineNaming = restored.Spec.MachineNaming
	return nil
}

func (dst *MachineSet) ConvertFrom(srcRaw conversion.Hub) error {
	src := srcRaw.(*clusterv1.MachineSet)

	if err := Convert_v1beta2_MachineSet_To_v1alpha4_MachineSet(src, dst, nil); err != nil {
		return err
	}

	if err := convertMachineSpecToObjectReference(&src.Spec.Template.Spec, &dst.Spec.Template.Spec, src.Namespace); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1beta2 conditions should not be automatically be converted into legacy conditions (v1alpha4).
	dst.Status.Conditions = nil

	// Reset replica counters from autogenerated conversions
	// NOTE: replica counters with a new semantic should not be automatically be converted into old replica counters.
	dst.Status.AvailableReplicas = 0
	dst.Status.ReadyReplicas = 0

	// Retrieve legacy conditions (v1alpha4), failureReason, failureMessage and replica counters from the deprecated field.
	if src.Status.Deprecated != nil {
		if src.Status.Deprecated.V1Beta1 != nil {
			if src.Status.Deprecated.V1Beta1.Conditions != nil {
				Convert_v1beta2_Deprecated_V1Beta1_Conditions_To_v1alpha4_Conditions(&src.Status.Deprecated.V1Beta1.Conditions, &dst.Status.Conditions)
			}
			dst.Status.FailureReason = src.Status.Deprecated.V1Beta1.FailureReason
			dst.Status.FailureMessage = src.Status.Deprecated.V1Beta1.FailureMessage
			dst.Status.ReadyReplicas = src.Status.Deprecated.V1Beta1.ReadyReplicas
			dst.Status.AvailableReplicas = src.Status.Deprecated.V1Beta1.AvailableReplicas
			dst.Status.FullyLabeledReplicas = src.Status.Deprecated.V1Beta1.FullyLabeledReplicas
		}
	}

	dst.Spec.MinReadySeconds = ptr.Deref(src.Spec.Template.Spec.MinReadySeconds, 0)

	dropEmptyStringsMachineSpec(&dst.Spec.Template.Spec)

	// Preserve Hub data on down-conversion except for metadata
	return utilconversion.MarshalData(src, dst)
}

func (src *MachineDeployment) ConvertTo(dstRaw conversion.Hub) error {
	dst := dstRaw.(*clusterv1.MachineDeployment)

	if err := Convert_v1alpha4_MachineDeployment_To_v1beta2_MachineDeployment(src, dst, nil); err != nil {
		return err
	}

	if err := convertMachineSpecToContractVersionedObjectReference(&src.Spec.Template.Spec, &dst.Spec.Template.Spec); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1alpha4 conditions should not be automatically be converted into v1beta2 conditions.
	dst.Status.Conditions = nil

	// Move legacy conditions (v1alpha4) and replica counters to the deprecated field.
	dst.Status.Deprecated = &clusterv1.MachineDeploymentDeprecatedStatus{}
	dst.Status.Deprecated.V1Beta1 = &clusterv1.MachineDeploymentV1Beta1DeprecatedStatus{}
	if src.Status.Conditions != nil {
		Convert_v1alpha4_Conditions_To_v1beta2_Deprecated_V1Beta1_Conditions(&src.Status.Conditions, &dst.Status.Deprecated.V1Beta1.Conditions)
	}
	dst.Status.Deprecated.V1Beta1.ReadyReplicas = src.Status.ReadyReplicas
	dst.Status.Deprecated.V1Beta1.AvailableReplicas = src.Status.AvailableReplicas
	dst.Status.Deprecated.V1Beta1.UpdatedReplicas = src.Status.UpdatedReplicas
	dst.Status.Deprecated.V1Beta1.UnavailableReplicas = src.Status.UnavailableReplicas

	dst.Spec.Template.Spec.MinReadySeconds = src.Spec.MinReadySeconds

	// Manually restore data.
	restored := &clusterv1.MachineDeployment{}
	ok, err := utilconversion.UnmarshalData(src, restored)
	if err != nil {
		return err
	}

	// Recover intent for bool values converted to *bool.
	clusterv1.Convert_bool_To_Pointer_bool(src.Spec.Paused, ok, restored.Spec.Paused, &dst.Spec.Paused)

	// Recover other values
	if ok {
		dst.Spec.Template.Spec.ReadinessGates = restored.Spec.Template.Spec.ReadinessGates
		dst.Spec.Template.Spec.Deletion.NodeDeletionTimeoutSeconds = restored.Spec.Template.Spec.Deletion.NodeDeletionTimeoutSeconds
		dst.Spec.Template.Spec.Deletion.NodeVolumeDetachTimeoutSeconds = restored.Spec.Template.Spec.Deletion.NodeVolumeDetachTimeoutSeconds
		dst.Spec.Rollout.After = restored.Spec.Rollout.After
		dst.Spec.Remediation = restored.Spec.Remediation
		dst.Spec.MachineNaming = restored.Spec.MachineNaming
		dst.Spec.Template.Spec.Taints = restored.Spec.Template.Spec.Taints
		dst.Status.Conditions = restored.Status.Conditions
		dst.Status.AvailableReplicas = restored.Status.AvailableReplicas
		dst.Status.ReadyReplicas = restored.Status.ReadyReplicas
		dst.Status.UpToDateReplicas = restored.Status.UpToDateReplicas
	}

	return nil
}

func (dst *MachineDeployment) ConvertFrom(srcRaw conversion.Hub) error {
	src := srcRaw.(*clusterv1.MachineDeployment)

	if err := Convert_v1beta2_MachineDeployment_To_v1alpha4_MachineDeployment(src, dst, nil); err != nil {
		return err
	}

	if err := convertMachineSpecToObjectReference(&src.Spec.Template.Spec, &dst.Spec.Template.Spec, src.Namespace); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1beta2 conditions should not be automatically be converted into legacy conditions (v1alpha4).
	dst.Status.Conditions = nil

	// Reset replica counters from autogenerated conversions
	// NOTE: replica counters with a new semantic should not be automatically be converted into old replica counters.
	dst.Status.AvailableReplicas = 0
	dst.Status.ReadyReplicas = 0

	// Retrieve legacy conditions (v1alpha4), failureReason, failureMessage and replica counters from the deprecated field.
	if src.Status.Deprecated != nil {
		if src.Status.Deprecated.V1Beta1 != nil {
			if src.Status.Deprecated.V1Beta1.Conditions != nil {
				Convert_v1beta2_Deprecated_V1Beta1_Conditions_To_v1alpha4_Conditions(&src.Status.Deprecated.V1Beta1.Conditions, &dst.Status.Conditions)
			}
			dst.Status.ReadyReplicas = src.Status.Deprecated.V1Beta1.ReadyReplicas
			dst.Status.AvailableReplicas = src.Status.Deprecated.V1Beta1.AvailableReplicas
			dst.Status.UpdatedReplicas = src.Status.Deprecated.V1Beta1.UpdatedReplicas
			dst.Status.UnavailableReplicas = src.Status.Deprecated.V1Beta1.UnavailableReplicas
		}
	}

	dst.Spec.MinReadySeconds = src.Spec.Template.Spec.MinReadySeconds

	dropEmptyStringsMachineSpec(&dst.Spec.Template.Spec)

	// Preserve Hub data on down-conversion except for metadata
	return utilconversion.MarshalData(src, dst)
}

func (src *MachineHealthCheck) ConvertTo(dstRaw conversion.Hub) error {
	dst := dstRaw.(*clusterv1.MachineHealthCheck)

	if err := Convert_v1alpha4_MachineHealthCheck_To_v1beta2_MachineHealthCheck(src, dst, nil); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1alpha4 conditions should not be automatically be converted into v1beta2 conditions.
	dst.Status.Conditions = nil

	// Move legacy conditions (v1alpha4) to the deprecated field.
	if src.Status.Conditions != nil {
		dst.Status.Deprecated = &clusterv1.MachineHealthCheckDeprecatedStatus{}
		dst.Status.Deprecated.V1Beta1 = &clusterv1.MachineHealthCheckV1Beta1DeprecatedStatus{}
		Convert_v1alpha4_Conditions_To_v1beta2_Deprecated_V1Beta1_Conditions(&src.Status.Conditions, &dst.Status.Deprecated.V1Beta1.Conditions)
	}

	// Manually restore data.
	restored := &clusterv1.MachineHealthCheck{}
	ok, err := utilconversion.UnmarshalData(src, restored)
	if err != nil {
		return err
	}

	dst.Spec.Checks.UnhealthyMachineConditions = restored.Spec.Checks.UnhealthyMachineConditions

	clusterv1.Convert_int32_To_Pointer_int32(src.Status.ExpectedMachines, ok, restored.Status.ExpectedMachines, &dst.Status.ExpectedMachines)
	clusterv1.Convert_int32_To_Pointer_int32(src.Status.CurrentHealthy, ok, restored.Status.CurrentHealthy, &dst.Status.CurrentHealthy)
	clusterv1.Convert_int32_To_Pointer_int32(src.Status.RemediationsAllowed, ok, restored.Status.RemediationsAllowed, &dst.Status.RemediationsAllowed)

	if !ok {
		return nil
	}

	dst.Status.Conditions = restored.Status.Conditions

	return nil
}

func (dst *MachineHealthCheck) ConvertFrom(srcRaw conversion.Hub) error {
	src := srcRaw.(*clusterv1.MachineHealthCheck)

	if err := Convert_v1beta2_MachineHealthCheck_To_v1alpha4_MachineHealthCheck(src, dst, nil); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1beta2 conditions should not be automatically be converted into legacy conditions (v1alpha4).
	dst.Status.Conditions = nil

	// Retrieve legacy conditions (v1alpha4) from the deprecated field.
	if src.Status.Deprecated != nil {
		if src.Status.Deprecated.V1Beta1 != nil {
			if src.Status.Deprecated.V1Beta1.Conditions != nil {
				Convert_v1beta2_Deprecated_V1Beta1_Conditions_To_v1alpha4_Conditions(&src.Status.Deprecated.V1Beta1.Conditions, &dst.Status.Conditions)
			}
		}
	}

	if dst.Spec.RemediationTemplate != nil {
		dst.Spec.RemediationTemplate.Namespace = src.Namespace
	}

	// Preserve Hub data on down-conversion except for metadata
	return utilconversion.MarshalData(src, dst)
}

func (src *MachinePool) ConvertTo(dstRaw conversion.Hub) error {
	dst := dstRaw.(*clusterv1.MachinePool)

	if err := Convert_v1alpha4_MachinePool_To_v1beta2_MachinePool(src, dst, nil); err != nil {
		return err
	}

	if err := convertMachineSpecToContractVersionedObjectReference(&src.Spec.Template.Spec, &dst.Spec.Template.Spec); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1alpha4 conditions should not be automatically be converted into v1beta2 conditions.
	dst.Status.Conditions = nil

	// Move legacy conditions (v1alpha4), failureReason, failureMessage and replica counters to the deprecated field.
	dst.Status.Deprecated = &clusterv1.MachinePoolDeprecatedStatus{}
	dst.Status.Deprecated.V1Beta1 = &clusterv1.MachinePoolV1Beta1DeprecatedStatus{}
	if src.Status.Conditions != nil {
		Convert_v1alpha4_Conditions_To_v1beta2_Deprecated_V1Beta1_Conditions(&src.Status.Conditions, &dst.Status.Deprecated.V1Beta1.Conditions)
	}
	dst.Status.Deprecated.V1Beta1.FailureReason = src.Status.FailureReason
	dst.Status.Deprecated.V1Beta1.FailureMessage = src.Status.FailureMessage
	dst.Status.Deprecated.V1Beta1.ReadyReplicas = src.Status.ReadyReplicas
	dst.Status.Deprecated.V1Beta1.AvailableReplicas = src.Status.AvailableReplicas
	dst.Status.Deprecated.V1Beta1.UnavailableReplicas = src.Status.UnavailableReplicas
	dst.Spec.Template.Spec.MinReadySeconds = src.Spec.MinReadySeconds

	// Manually restore data.
	restored := &clusterv1.MachinePool{}
	ok, err := utilconversion.UnmarshalData(src, restored)
	if err != nil {
		return err
	}

	// Recover intent for bool values converted to *bool.
	initialization := clusterv1.MachinePoolInitializationStatus{}
	restoredBootstrapDataSecretCreated := restored.Status.Initialization.BootstrapDataSecretCreated
	restoredInfrastructureProvisioned := restored.Status.Initialization.InfrastructureProvisioned
	clusterv1.Convert_bool_To_Pointer_bool(src.Status.BootstrapReady, ok, restoredBootstrapDataSecretCreated, &initialization.BootstrapDataSecretCreated)
	clusterv1.Convert_bool_To_Pointer_bool(src.Status.InfrastructureReady, ok, restoredInfrastructureProvisioned, &initialization.InfrastructureProvisioned)
	if !reflect.DeepEqual(initialization, clusterv1.MachinePoolInitializationStatus{}) {
		dst.Status.Initialization = initialization
	}

	// Recover other values
	if ok {
		dst.Spec.Template.Spec.ReadinessGates = restored.Spec.Template.Spec.ReadinessGates
		dst.Spec.Template.Spec.Deletion.NodeDeletionTimeoutSeconds = restored.Spec.Template.Spec.Deletion.NodeDeletionTimeoutSeconds
		dst.Spec.Template.Spec.Deletion.NodeVolumeDetachTimeoutSeconds = restored.Spec.Template.Spec.Deletion.NodeVolumeDetachTimeoutSeconds
		dst.Spec.Template.Spec.Taints = restored.Spec.Template.Spec.Taints
		dst.Status.Conditions = restored.Status.Conditions
		dst.Status.AvailableReplicas = restored.Status.AvailableReplicas
		dst.Status.ReadyReplicas = restored.Status.ReadyReplicas
		dst.Status.UpToDateReplicas = restored.Status.UpToDateReplicas
	}

	return nil
}

func (dst *MachinePool) ConvertFrom(srcRaw conversion.Hub) error {
	src := srcRaw.(*clusterv1.MachinePool)

	if err := Convert_v1beta2_MachinePool_To_v1alpha4_MachinePool(src, dst, nil); err != nil {
		return err
	}

	if err := convertMachineSpecToObjectReference(&src.Spec.Template.Spec, &dst.Spec.Template.Spec, src.Namespace); err != nil {
		return err
	}

	// Reset conditions from autogenerated conversions
	// NOTE: v1beta2 conditions should not be automatically be converted into legacy conditions (v1alpha4).
	dst.Status.Conditions = nil

	// Reset replica counters from autogenerated conversions
	// NOTE: replica counters with a new semantic should not be automatically be converted into old replica counters.
	dst.Status.ReadyReplicas = 0
	dst.Status.AvailableReplicas = 0

	// Retrieve legacy conditions (v1alpha4), failureReason, failureMessage and replica counters from the deprecated field.
	if src.Status.Deprecated != nil {
		if src.Status.Deprecated.V1Beta1 != nil {
			if src.Status.Deprecated.V1Beta1.Conditions != nil {
				Convert_v1beta2_Deprecated_V1Beta1_Conditions_To_v1alpha4_Conditions(&src.Status.Deprecated.V1Beta1.Conditions, &dst.Status.Conditions)
			}
			dst.Status.FailureReason = src.Status.Deprecated.V1Beta1.FailureReason
			dst.Status.FailureMessage = src.Status.Deprecated.V1Beta1.FailureMessage
			dst.Status.ReadyReplicas = src.Status.Deprecated.V1Beta1.ReadyReplicas
			dst.Status.AvailableReplicas = src.Status.Deprecated.V1Beta1.AvailableReplicas
			dst.Status.UnavailableReplicas = src.Status.Deprecated.V1Beta1.UnavailableReplicas
		}
	}

	// Move initialization to old fields
	dst.Status.BootstrapReady = ptr.Deref(src.Status.Initialization.BootstrapDataSecretCreated, false)
	dst.Status.InfrastructureReady = ptr.Deref(src.Status.Initialization.InfrastructureProvisioned, false)

	dst.Spec.MinReadySeconds = src.Spec.Template.Spec.MinReadySeconds

	dropEmptyStringsMachineSpec(&dst.Spec.Template.Spec)

	// Preserve Hub data on down-conversion except for metadata
	return utilconversion.MarshalData(src, dst)
}

func Convert_v1alpha4_MachineStatus_To_v1beta2_MachineStatus(in *MachineStatus, out *clusterv1.MachineStatus, s apimachineryconversion.Scope) error {
	// Status.version has been removed in v1beta1, thus requiring custom conversion function. the information will be dropped.
	if err := autoConvert_v1alpha4_MachineStatus_To_v1beta2_MachineStatus(in, out, s); err != nil {
		return err
	}
	if in.LastUpdated != nil && !reflect.DeepEqual(in.LastUpdated, &metav1.Time{}) {
		out.LastUpdated = *in.LastUpdated
	}
	if in.NodeRef != nil && !reflect.DeepEqual(in.NodeRef, &corev1.ObjectReference{}) {
		out.NodeRef.Name = in.NodeRef.Name
	}
	return nil
}

func Convert_v1beta2_ClusterClassSpec_To_v1alpha4_ClusterClassSpec(in *clusterv1.ClusterClassSpec, out *ClusterClassSpec, s apimachineryconversion.Scope) error {
	// spec.{variables,patches} has been added with v1beta1.
	return autoConvert_v1beta2_ClusterClassSpec_To_v1alpha4_ClusterClassSpec(in, out, s)
}

func Convert_v1alpha4_ControlPlaneClass_To_v1beta2_ControlPlaneClass(in *ControlPlaneClass, out *clusterv1.ControlPlaneClass, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_ControlPlaneClass_To_v1beta2_ControlPlaneClass(in, out, s); err != nil {
		return err
	}

	convert_v1alpha4_LocalObjectTemplate_To_v1beta2_ClusterClassTemplateReference(&in.LocalObjectTemplate, &out.TemplateRef, s)
	if in.MachineInfrastructure != nil {
		if err := Convert_v1alpha4_LocalObjectTemplate_To_v1beta2_ControlPlaneClassMachineInfrastructureTemplate(in.MachineInfrastructure, &out.MachineInfrastructure, s); err != nil {
			return err
		}
	}
	return nil
}

func Convert_v1beta2_InfrastructureClass_To_v1alpha4_LocalObjectTemplate(in *clusterv1.InfrastructureClass, out *LocalObjectTemplate, s apimachineryconversion.Scope) error {
	if in == nil {
		return nil
	}

	Convert_v1beta2_ClusterClassTemplateReference_To_v1alpha4_LocalObjectTemplate(&in.TemplateRef, out, s)
	return nil
}

func Convert_v1alpha4_LocalObjectTemplate_To_v1beta2_InfrastructureClass(in *LocalObjectTemplate, out *clusterv1.InfrastructureClass, s apimachineryconversion.Scope) error {
	if in == nil {
		return nil
	}

	convert_v1alpha4_LocalObjectTemplate_To_v1beta2_ClusterClassTemplateReference(in, &out.TemplateRef, s)
	return nil
}

func Convert_v1beta2_MachineSpec_To_v1alpha4_MachineSpec(in *clusterv1.MachineSpec, out *MachineSpec, s apimachineryconversion.Scope) error {
	// spec.nodeDeletionTimeout was added in v1beta1.
	// ReadinessGates was added in v1beta1.
	if err := autoConvert_v1beta2_MachineSpec_To_v1alpha4_MachineSpec(in, out, s); err != nil {
		return err
	}
	out.NodeDrainTimeout = clusterv1.ConvertFromSeconds(in.Deletion.NodeDrainTimeoutSeconds)
	return nil
}

func Convert_v1beta2_MachineDeploymentSpec_To_v1alpha4_MachineDeploymentSpec(in *clusterv1.MachineDeploymentSpec, out *MachineDeploymentSpec, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1beta2_MachineDeploymentSpec_To_v1alpha4_MachineDeploymentSpec(in, out, s); err != nil {
		return err
	}
	if !reflect.DeepEqual(in.Rollout.Strategy, clusterv1.MachineDeploymentRolloutStrategy{}) {
		out.Strategy = &MachineDeploymentStrategy{}
		out.Strategy.Type = MachineDeploymentStrategyType(in.Rollout.Strategy.Type)
		if !reflect.DeepEqual(in.Rollout.Strategy.RollingUpdate, clusterv1.MachineDeploymentRolloutStrategyRollingUpdate{}) {
			out.Strategy.RollingUpdate = &MachineRollingUpdateDeployment{}
			if err := Convert_v1beta2_MachineDeploymentRolloutStrategyRollingUpdate_To_v1alpha4_MachineRollingUpdateDeployment(&in.Rollout.Strategy.RollingUpdate, out.Strategy.RollingUpdate, s); err != nil {
				return err
			}
		}
	}
	if in.Deletion.Order != "" {
		if out.Strategy == nil {
			out.Strategy = &MachineDeploymentStrategy{}
		}
		if out.Strategy.RollingUpdate == nil {
			out.Strategy.RollingUpdate = &MachineRollingUpdateDeployment{}
		}
		out.Strategy.RollingUpdate.DeletePolicy = ptr.To(string(in.Deletion.Order))
	}

	return nil
}

func Convert_v1alpha4_ClusterSpec_To_v1beta2_ClusterSpec(in *ClusterSpec, out *clusterv1.ClusterSpec, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_ClusterSpec_To_v1beta2_ClusterSpec(in, out, s); err != nil {
		return err
	}
	if in.ClusterNetwork != nil {
		if err := Convert_v1alpha4_ClusterNetwork_To_v1beta2_ClusterNetwork(in.ClusterNetwork, &out.ClusterNetwork, s); err != nil {
			return err
		}
	}
	if in.Topology != nil {
		if err := Convert_v1alpha4_Topology_To_v1beta2_Topology(in.Topology, &out.Topology, s); err != nil {
			return err
		}
	}
	return nil
}

func Convert_v1beta2_ClusterSpec_To_v1alpha4_ClusterSpec(in *clusterv1.ClusterSpec, out *ClusterSpec, s apimachineryconversion.Scope) error { // AvailabilityGates was added in v1alpha4.
	if err := autoConvert_v1beta2_ClusterSpec_To_v1alpha4_ClusterSpec(in, out, s); err != nil {
		return err
	}
	if !reflect.DeepEqual(in.ClusterNetwork, clusterv1.ClusterNetwork{}) {
		out.ClusterNetwork = &ClusterNetwork{}
		if err := Convert_v1beta2_ClusterNetwork_To_v1alpha4_ClusterNetwork(&in.ClusterNetwork, out.ClusterNetwork, s); err != nil {
			return err
		}
	}
	if !reflect.DeepEqual(in.Topology, clusterv1.Topology{}) {
		out.Topology = &Topology{}
		if err := Convert_v1beta2_Topology_To_v1alpha4_Topology(&in.Topology, out.Topology, s); err != nil {
			return err
		}
	}

	return nil
}

func Convert_v1alpha4_ClusterNetwork_To_v1beta2_ClusterNetwork(in *ClusterNetwork, out *clusterv1.ClusterNetwork, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_ClusterNetwork_To_v1beta2_ClusterNetwork(in, out, s); err != nil {
		return err
	}
	if in.Services != nil {
		if err := autoConvert_v1alpha4_NetworkRanges_To_v1beta2_NetworkRanges(in.Services, &out.Services, s); err != nil {
			return err
		}
	}
	if in.Pods != nil {
		if err := autoConvert_v1alpha4_NetworkRanges_To_v1beta2_NetworkRanges(in.Pods, &out.Pods, s); err != nil {
			return err
		}
	}

	return nil
}

func Convert_v1beta2_ClusterNetwork_To_v1alpha4_ClusterNetwork(in *clusterv1.ClusterNetwork, out *ClusterNetwork, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1beta2_ClusterNetwork_To_v1alpha4_ClusterNetwork(in, out, s); err != nil {
		return err
	}
	if !reflect.DeepEqual(in.Services, clusterv1.NetworkRanges{}) {
		out.Services = &NetworkRanges{}
		if err := autoConvert_v1beta2_NetworkRanges_To_v1alpha4_NetworkRanges(&in.Services, out.Services, s); err != nil {
			return err
		}
	}

	if !reflect.DeepEqual(in.Pods, clusterv1.NetworkRanges{}) {
		out.Pods = &NetworkRanges{}
		if err := autoConvert_v1beta2_NetworkRanges_To_v1alpha4_NetworkRanges(&in.Pods, out.Pods, s); err != nil {
			return err
		}
	}

	return nil
}

func Convert_v1beta2_ClusterStatus_To_v1alpha4_ClusterStatus(in *clusterv1.ClusterStatus, out *ClusterStatus, s apimachineryconversion.Scope) error {
	// V1Beta2 was added in v1beta1.
	if err := autoConvert_v1beta2_ClusterStatus_To_v1alpha4_ClusterStatus(in, out, s); err != nil {
		return err
	}

	// Move FailureDomains
	if in.FailureDomains != nil {
		out.FailureDomains = FailureDomains{}
		for _, fd := range in.FailureDomains {
			out.FailureDomains[fd.Name] = FailureDomainSpec{
				ControlPlane: ptr.Deref(fd.ControlPlane, false),
				Attributes:   fd.Attributes,
			}
		}
	}

	return nil
}

func Convert_v1beta2_Topology_To_v1alpha4_Topology(in *clusterv1.Topology, out *Topology, s apimachineryconversion.Scope) error {
	// spec.topology.variables has been added with v1beta1.
	if err := autoConvert_v1beta2_Topology_To_v1alpha4_Topology(in, out, s); err != nil {
		return err
	}
	if !reflect.DeepEqual(in.Workers, clusterv1.WorkersTopology{}) {
		out.Workers = &WorkersTopology{}
		if err := autoConvert_v1beta2_WorkersTopology_To_v1alpha4_WorkersTopology(&in.Workers, out.Workers, s); err != nil {
			return err
		}
	}
	out.Class = in.ClassRef.Name
	return nil
}

// Convert_v1beta2_MachineDeploymentTopology_To_v1alpha4_MachineDeploymentTopology is an autogenerated conversion function.
func Convert_v1beta2_MachineDeploymentTopology_To_v1alpha4_MachineDeploymentTopology(in *clusterv1.MachineDeploymentTopology, out *MachineDeploymentTopology, s apimachineryconversion.Scope) error {
	// MachineDeploymentTopology.FailureDomain has been added with v1beta1.
	return autoConvert_v1beta2_MachineDeploymentTopology_To_v1alpha4_MachineDeploymentTopology(in, out, s)
}

func Convert_v1alpha4_MachineDeploymentClass_To_v1beta2_MachineDeploymentClass(in *MachineDeploymentClass, out *clusterv1.MachineDeploymentClass, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_MachineDeploymentClass_To_v1beta2_MachineDeploymentClass(in, out, s); err != nil {
		return err
	}
	if err := Convert_v1alpha4_ObjectMeta_To_v1beta2_ObjectMeta(&in.Template.Metadata, &out.Metadata, s); err != nil {
		return err
	}
	if err := Convert_v1alpha4_LocalObjectTemplate_To_v1beta2_MachineDeploymentClassBootstrapTemplate(&in.Template.Bootstrap, &out.Bootstrap, s); err != nil {
		return err
	}
	if err := Convert_v1alpha4_LocalObjectTemplate_To_v1beta2_MachineDeploymentClassInfrastructureTemplate(&in.Template.Infrastructure, &out.Infrastructure, s); err != nil {
		return err
	}
	return nil
}

func Convert_v1beta2_MachineDeploymentClass_To_v1alpha4_MachineDeploymentClass(in *clusterv1.MachineDeploymentClass, out *MachineDeploymentClass, s apimachineryconversion.Scope) error {
	// machineDeploymentClass.machineHealthCheck has been added with v1beta1.
	if err := autoConvert_v1beta2_MachineDeploymentClass_To_v1alpha4_MachineDeploymentClass(in, out, s); err != nil {
		return err
	}
	if err := Convert_v1beta2_ObjectMeta_To_v1alpha4_ObjectMeta(&in.Metadata, &out.Template.Metadata, s); err != nil {
		return err
	}
	if err := Convert_v1beta2_MachineDeploymentClassBootstrapTemplate_To_v1alpha4_LocalObjectTemplate(&in.Bootstrap, &out.Template.Bootstrap, s); err != nil {
		return err
	}
	if err := Convert_v1beta2_MachineDeploymentClassInfrastructureTemplate_To_v1alpha4_LocalObjectTemplate(&in.Infrastructure, &out.Template.Infrastructure, s); err != nil {
		return err
	}
	return nil
}

func Convert_v1beta2_ControlPlaneClass_To_v1alpha4_ControlPlaneClass(in *clusterv1.ControlPlaneClass, out *ControlPlaneClass, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1beta2_ControlPlaneClass_To_v1alpha4_ControlPlaneClass(in, out, s); err != nil {
		return err
	}

	Convert_v1beta2_ClusterClassTemplateReference_To_v1alpha4_LocalObjectTemplate(&in.TemplateRef, &out.LocalObjectTemplate, s)
	if in.MachineInfrastructure.TemplateRef.IsDefined() {
		out.MachineInfrastructure = &LocalObjectTemplate{}
		if err := Convert_v1beta2_ControlPlaneClassMachineInfrastructureTemplate_To_v1alpha4_LocalObjectTemplate(&in.MachineInfrastructure, out.MachineInfrastructure, s); err != nil {
			return err
		}
	}
	return nil
}

func Convert_v1alpha4_Topology_To_v1beta2_Topology(in *Topology, out *clusterv1.Topology, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_Topology_To_v1beta2_Topology(in, out, s); err != nil {
		return err
	}
	if in.Workers != nil {
		if err := autoConvert_v1alpha4_WorkersTopology_To_v1beta2_WorkersTopology(in.Workers, &out.Workers, s); err != nil {
			return err
		}
	}
	out.ClassRef.Name = in.Class
	return nil
}

func Convert_v1beta2_ControlPlaneTopology_To_v1alpha4_ControlPlaneTopology(in *clusterv1.ControlPlaneTopology, out *ControlPlaneTopology, s apimachineryconversion.Scope) error {
	// controlPlaneTopology.nodeDrainTimeout has been added with v1beta1.
	return autoConvert_v1beta2_ControlPlaneTopology_To_v1alpha4_ControlPlaneTopology(in, out, s)
}

func Convert_v1beta2_MachineStatus_To_v1alpha4_MachineStatus(in *clusterv1.MachineStatus, out *MachineStatus, s apimachineryconversion.Scope) error {
	// MachineStatus.CertificatesExpiryDate has been added in v1beta1.
	// V1Beta2 was added in v1beta1.
	if err := autoConvert_v1beta2_MachineStatus_To_v1alpha4_MachineStatus(in, out, s); err != nil {
		return err
	}
	if !reflect.DeepEqual(in.LastUpdated, metav1.Time{}) {
		out.LastUpdated = ptr.To(in.LastUpdated)
	}
	if in.NodeRef.IsDefined() {
		out.NodeRef = &corev1.ObjectReference{
			Name:       in.NodeRef.Name,
			APIVersion: corev1.SchemeGroupVersion.String(),
			Kind:       "Node",
		}
	}
	return nil
}

func Convert_v1beta2_ClusterClass_To_v1alpha4_ClusterClass(in *clusterv1.ClusterClass, out *ClusterClass, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1beta2_ClusterClass_To_v1alpha4_ClusterClass(in, out, s); err != nil {
		return err
	}

	if out.Spec.Infrastructure.Ref != nil {
		out.Spec.Infrastructure.Ref.Namespace = in.Namespace
	}
	if out.Spec.ControlPlane.Ref != nil {
		out.Spec.ControlPlane.Ref.Namespace = in.Namespace
	}
	if out.Spec.ControlPlane.MachineInfrastructure != nil && out.Spec.ControlPlane.MachineInfrastructure.Ref != nil {
		out.Spec.ControlPlane.MachineInfrastructure.Ref.Namespace = in.Namespace
	}
	for _, md := range out.Spec.Workers.MachineDeployments {
		if md.Template.Bootstrap.Ref != nil {
			md.Template.Bootstrap.Ref.Namespace = in.Namespace
		}
		if md.Template.Infrastructure.Ref != nil {
			md.Template.Infrastructure.Ref.Namespace = in.Namespace
		}
	}
	return nil
}

func Convert_v1beta2_WorkersClass_To_v1alpha4_WorkersClass(in *clusterv1.WorkersClass, out *WorkersClass, s apimachineryconversion.Scope) error {
	// WorkersClass.MachinePools has been added in v1beta1.
	return autoConvert_v1beta2_WorkersClass_To_v1alpha4_WorkersClass(in, out, s)
}

func Convert_v1beta2_WorkersTopology_To_v1alpha4_WorkersTopology(in *clusterv1.WorkersTopology, out *WorkersTopology, s apimachineryconversion.Scope) error {
	// WorkersTopology.MachinePools has been added in v1beta1.
	return autoConvert_v1beta2_WorkersTopology_To_v1alpha4_WorkersTopology(in, out, s)
}

func Convert_v1beta2_MachineSetSpec_To_v1alpha4_MachineSetSpec(in *clusterv1.MachineSetSpec, out *MachineSetSpec, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1beta2_MachineSetSpec_To_v1alpha4_MachineSetSpec(in, out, s); err != nil {
		return err
	}

	out.DeletePolicy = string(in.Deletion.Order)
	return nil
}

func Convert_v1beta2_MachineDeploymentStatus_To_v1alpha4_MachineDeploymentStatus(in *clusterv1.MachineDeploymentStatus, out *MachineDeploymentStatus, s apimachineryconversion.Scope) error {
	// V1Beta2 was added in v1beta1.
	return autoConvert_v1beta2_MachineDeploymentStatus_To_v1alpha4_MachineDeploymentStatus(in, out, s)
}

func Convert_v1beta2_MachineSetStatus_To_v1alpha4_MachineSetStatus(in *clusterv1.MachineSetStatus, out *MachineSetStatus, s apimachineryconversion.Scope) error {
	// V1Beta2 was added in v1beta1.
	return autoConvert_v1beta2_MachineSetStatus_To_v1alpha4_MachineSetStatus(in, out, s)
}

func Convert_v1alpha4_MachineHealthCheckSpec_To_v1beta2_MachineHealthCheckSpec(in *MachineHealthCheckSpec, out *clusterv1.MachineHealthCheckSpec, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_MachineHealthCheckSpec_To_v1beta2_MachineHealthCheckSpec(in, out, s); err != nil {
		return err
	}

	for _, c := range in.UnhealthyConditions {
		out.Checks.UnhealthyNodeConditions = append(out.Checks.UnhealthyNodeConditions, clusterv1.UnhealthyNodeCondition{
			Type:           c.Type,
			Status:         c.Status,
			TimeoutSeconds: clusterv1.ConvertToSeconds(&c.Timeout),
		})
	}
	out.Checks.NodeStartupTimeoutSeconds = clusterv1.ConvertToSeconds(in.NodeStartupTimeout)
	out.Remediation.TriggerIf.UnhealthyLessThanOrEqualTo = in.MaxUnhealthy
	out.Remediation.TriggerIf.UnhealthyInRange = ptr.Deref(in.UnhealthyRange, "")
	if in.RemediationTemplate != nil {
		if err := clusterv1beta1.Convert_v1_ObjectReference_To_v1beta2_MachineHealthCheckRemediationTemplateReference(in.RemediationTemplate, &out.Remediation.TemplateRef, s); err != nil {
			return err
		}
	}

	return nil
}

func Convert_v1beta2_MachineHealthCheckSpec_To_v1alpha4_MachineHealthCheckSpec(in *clusterv1.MachineHealthCheckSpec, out *MachineHealthCheckSpec, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1beta2_MachineHealthCheckSpec_To_v1alpha4_MachineHealthCheckSpec(in, out, s); err != nil {
		return err
	}

	for _, c := range in.Checks.UnhealthyNodeConditions {
		out.UnhealthyConditions = append(out.UnhealthyConditions, UnhealthyCondition{
			Type:    c.Type,
			Status:  c.Status,
			Timeout: ptr.Deref(clusterv1.ConvertFromSeconds(c.TimeoutSeconds), metav1.Duration{}),
		})
	}
	out.NodeStartupTimeout = clusterv1.ConvertFromSeconds(in.Checks.NodeStartupTimeoutSeconds)
	out.MaxUnhealthy = in.Remediation.TriggerIf.UnhealthyLessThanOrEqualTo
	if in.Remediation.TriggerIf.UnhealthyInRange != "" {
		out.UnhealthyRange = ptr.To(in.Remediation.TriggerIf.UnhealthyInRange)
	}
	if in.Remediation.TemplateRef.IsDefined() {
		out.RemediationTemplate = &corev1.ObjectReference{}
		if err := clusterv1beta1.Convert_v1beta2_MachineHealthCheckRemediationTemplateReference_To_v1_ObjectReference(&in.Remediation.TemplateRef, out.RemediationTemplate, s); err != nil {
			return err
		}
	}

	return nil
}

func Convert_v1beta2_MachineHealthCheckStatus_To_v1alpha4_MachineHealthCheckStatus(in *clusterv1.MachineHealthCheckStatus, out *MachineHealthCheckStatus, s apimachineryconversion.Scope) error {
	// V1Beta2 was added in v1beta1.
	return autoConvert_v1beta2_MachineHealthCheckStatus_To_v1alpha4_MachineHealthCheckStatus(in, out, s)
}

func Convert_v1alpha4_ClusterStatus_To_v1beta2_ClusterStatus(in *ClusterStatus, out *clusterv1.ClusterStatus, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_ClusterStatus_To_v1beta2_ClusterStatus(in, out, s); err != nil {
		return err
	}

	// Move FailureDomains
	if in.FailureDomains != nil {
		out.FailureDomains = []clusterv1.FailureDomain{}
		domainNames := slices.Collect(maps.Keys(in.FailureDomains))
		sort.Strings(domainNames)
		for _, name := range domainNames {
			fd := in.FailureDomains[name]
			out.FailureDomains = append(out.FailureDomains, clusterv1.FailureDomain{
				Name:         name,
				ControlPlane: nil, // Note: this field will be computed in ConvertTo
				Attributes:   fd.Attributes,
			})
		}
	}

	return nil
}

func Convert_v1alpha4_MachineDeploymentSpec_To_v1beta2_MachineDeploymentSpec(in *MachineDeploymentSpec, out *clusterv1.MachineDeploymentSpec, s apimachineryconversion.Scope) error {
	// NOTE: v1beta2 MachineDeploymentSpec does not have ProgressDeadlineSeconds anymore. But it's fine to just lose this field it was never used.
	if err := autoConvert_v1alpha4_MachineDeploymentSpec_To_v1beta2_MachineDeploymentSpec(in, out, s); err != nil {
		return err
	}
	if in.Strategy != nil {
		out.Rollout.Strategy.Type = clusterv1.MachineDeploymentRolloutStrategyType(in.Strategy.Type)
		if in.Strategy.RollingUpdate != nil {
			if err := Convert_v1alpha4_MachineRollingUpdateDeployment_To_v1beta2_MachineDeploymentRolloutStrategyRollingUpdate(in.Strategy.RollingUpdate, &out.Rollout.Strategy.RollingUpdate, s); err != nil {
				return err
			}
		}
		if in.Strategy.RollingUpdate != nil && in.Strategy.RollingUpdate.DeletePolicy != nil {
			out.Deletion.Order = clusterv1.MachineSetDeletionOrder(*in.Strategy.RollingUpdate.DeletePolicy)
		}
	}

	return nil
}

func Convert_v1alpha4_MachineDeploymentStatus_To_v1beta2_MachineDeploymentStatus(in *MachineDeploymentStatus, out *clusterv1.MachineDeploymentStatus, s apimachineryconversion.Scope) error {
	return autoConvert_v1alpha4_MachineDeploymentStatus_To_v1beta2_MachineDeploymentStatus(in, out, s)
}

func Convert_v1alpha4_MachineSetStatus_To_v1beta2_MachineSetStatus(in *MachineSetStatus, out *clusterv1.MachineSetStatus, s apimachineryconversion.Scope) error {
	return autoConvert_v1alpha4_MachineSetStatus_To_v1beta2_MachineSetStatus(in, out, s)
}

func Convert_v1_Condition_To_v1alpha4_Condition(_ *metav1.Condition, _ *Condition, _ apimachineryconversion.Scope) error {
	// NOTE: v1beta2 conditions should not be automatically converted into legacy (v1alpha4) conditions.
	return nil
}

func Convert_v1alpha4_Condition_To_v1_Condition(_ *Condition, _ *metav1.Condition, _ apimachineryconversion.Scope) error {
	// NOTE: legacy (v1alpha4) conditions should not be automatically converted into v1beta2 conditions.
	return nil
}

func Convert_v1beta2_Deprecated_V1Beta1_Conditions_To_v1alpha4_Conditions(in *clusterv1.Conditions, out *Conditions) {
	*out = make(Conditions, len(*in))
	for i := range *in {
		(*out)[i] = *(*Condition)(unsafe.Pointer(&(*in)[i]))
	}
}

func Convert_v1alpha4_Conditions_To_v1beta2_Deprecated_V1Beta1_Conditions(in *Conditions, out *clusterv1.Conditions) {
	*out = make(clusterv1.Conditions, len(*in))
	for i := range *in {
		(*out)[i] = *(*clusterv1.Condition)(unsafe.Pointer(&(*in)[i]))
	}
}

func Convert_v1alpha4_MachineSetSpec_To_v1beta2_MachineSetSpec(in *MachineSetSpec, out *clusterv1.MachineSetSpec, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_MachineSetSpec_To_v1beta2_MachineSetSpec(in, out, s); err != nil {
		return err
	}

	out.Deletion.Order = clusterv1.MachineSetDeletionOrder(in.DeletePolicy)
	return nil
}

func Convert_v1beta2_MachinePoolStatus_To_v1alpha4_MachinePoolStatus(in *clusterv1.MachinePoolStatus, out *MachinePoolStatus, s apimachineryconversion.Scope) error {
	// V1Beta2 was added in v1beta1
	return autoConvert_v1beta2_MachinePoolStatus_To_v1alpha4_MachinePoolStatus(in, out, s)
}

func Convert_v1alpha4_MachinePoolStatus_To_v1beta2_MachinePoolStatus(in *MachinePoolStatus, out *clusterv1.MachinePoolStatus, scope apimachineryconversion.Scope) error {
	return autoConvert_v1alpha4_MachinePoolStatus_To_v1beta2_MachinePoolStatus(in, out, scope)
}

func Convert_v1alpha4_MachineSpec_To_v1beta2_MachineSpec(in *MachineSpec, out *clusterv1.MachineSpec, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_MachineSpec_To_v1beta2_MachineSpec(in, out, s); err != nil {
		return err
	}
	out.Deletion.NodeDrainTimeoutSeconds = clusterv1.ConvertToSeconds(in.NodeDrainTimeout)
	return nil
}

func Convert_v1alpha4_LocalObjectTemplate_To_v1beta2_ControlPlaneClassMachineInfrastructureTemplate(in *LocalObjectTemplate, out *clusterv1.ControlPlaneClassMachineInfrastructureTemplate, s apimachineryconversion.Scope) error {
	convert_v1alpha4_LocalObjectTemplate_To_v1beta2_ClusterClassTemplateReference(in, &out.TemplateRef, s)
	return nil
}

func Convert_v1alpha4_LocalObjectTemplate_To_v1beta2_MachineDeploymentClassBootstrapTemplate(in *LocalObjectTemplate, out *clusterv1.MachineDeploymentClassBootstrapTemplate, s apimachineryconversion.Scope) error {
	convert_v1alpha4_LocalObjectTemplate_To_v1beta2_ClusterClassTemplateReference(in, &out.TemplateRef, s)
	return nil
}

func Convert_v1alpha4_LocalObjectTemplate_To_v1beta2_MachineDeploymentClassInfrastructureTemplate(in *LocalObjectTemplate, out *clusterv1.MachineDeploymentClassInfrastructureTemplate, s apimachineryconversion.Scope) error {
	convert_v1alpha4_LocalObjectTemplate_To_v1beta2_ClusterClassTemplateReference(in, &out.TemplateRef, s)
	return nil
}

func convert_v1alpha4_LocalObjectTemplate_To_v1beta2_ClusterClassTemplateReference(in *LocalObjectTemplate, out *clusterv1.ClusterClassTemplateReference, _ apimachineryconversion.Scope) {
	if in == nil || in.Ref == nil {
		return
	}

	*out = clusterv1.ClusterClassTemplateReference{
		Kind:       in.Ref.Kind,
		Name:       in.Ref.Name,
		APIVersion: in.Ref.APIVersion,
	}
}

func Convert_v1beta2_ControlPlaneClassMachineInfrastructureTemplate_To_v1alpha4_LocalObjectTemplate(in *clusterv1.ControlPlaneClassMachineInfrastructureTemplate, out *LocalObjectTemplate, s apimachineryconversion.Scope) error {
	Convert_v1beta2_ClusterClassTemplateReference_To_v1alpha4_LocalObjectTemplate(&in.TemplateRef, out, s)
	return nil
}

func Convert_v1beta2_MachineDeploymentClassBootstrapTemplate_To_v1alpha4_LocalObjectTemplate(in *clusterv1.MachineDeploymentClassBootstrapTemplate, out *LocalObjectTemplate, s apimachineryconversion.Scope) error {
	Convert_v1beta2_ClusterClassTemplateReference_To_v1alpha4_LocalObjectTemplate(&in.TemplateRef, out, s)
	return nil
}

func Convert_v1beta2_MachineDeploymentClassInfrastructureTemplate_To_v1alpha4_LocalObjectTemplate(in *clusterv1.MachineDeploymentClassInfrastructureTemplate, out *LocalObjectTemplate, s apimachineryconversion.Scope) error {
	Convert_v1beta2_ClusterClassTemplateReference_To_v1alpha4_LocalObjectTemplate(&in.TemplateRef, out, s)
	return nil
}

func Convert_v1beta2_ClusterClassTemplateReference_To_v1alpha4_LocalObjectTemplate(in *clusterv1.ClusterClassTemplateReference, out *LocalObjectTemplate, _ apimachineryconversion.Scope) {
	if in == nil {
		return
	}

	out.Ref = &corev1.ObjectReference{
		Kind:       in.Kind,
		Name:       in.Name,
		APIVersion: in.APIVersion,
	}
}

func Convert_v1alpha4_MachinePoolSpec_To_v1beta2_MachinePoolSpec(in *MachinePoolSpec, out *clusterv1.MachinePoolSpec, s apimachineryconversion.Scope) error {
	return autoConvert_v1alpha4_MachinePoolSpec_To_v1beta2_MachinePoolSpec(in, out, s)
}

func Convert_v1alpha4_MachineRollingUpdateDeployment_To_v1beta2_MachineDeploymentRolloutStrategyRollingUpdate(in *MachineRollingUpdateDeployment, out *clusterv1.MachineDeploymentRolloutStrategyRollingUpdate, _ apimachineryconversion.Scope) error {
	out.MaxUnavailable = in.MaxUnavailable
	out.MaxSurge = in.MaxSurge
	return nil
}

func Convert_v1beta2_MachineDeploymentRolloutStrategyRollingUpdate_To_v1alpha4_MachineRollingUpdateDeployment(in *clusterv1.MachineDeploymentRolloutStrategyRollingUpdate, out *MachineRollingUpdateDeployment, _ apimachineryconversion.Scope) error {
	out.MaxUnavailable = in.MaxUnavailable
	out.MaxSurge = in.MaxSurge
	return nil
}

func Convert_v1alpha4_Bootstrap_To_v1beta2_Bootstrap(in *Bootstrap, out *clusterv1.Bootstrap, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1alpha4_Bootstrap_To_v1beta2_Bootstrap(in, out, s); err != nil {
		return err
	}
	if in.ConfigRef != nil {
		if err := clusterv1beta1.Convert_v1_ObjectReference_To_v1beta2_ContractVersionedObjectReference(in.ConfigRef, &out.ConfigRef, s); err != nil {
			return err
		}
	}
	return nil
}

func Convert_v1beta2_Bootstrap_To_v1alpha4_Bootstrap(in *clusterv1.Bootstrap, out *Bootstrap, s apimachineryconversion.Scope) error {
	if err := autoConvert_v1beta2_Bootstrap_To_v1alpha4_Bootstrap(in, out, s); err != nil {
		return err
	}
	if in.ConfigRef.IsDefined() {
		out.ConfigRef = &corev1.ObjectReference{}
		if err := clusterv1beta1.Convert_v1beta2_ContractVersionedObjectReference_To_v1_ObjectReference(&in.ConfigRef, out.ConfigRef, s); err != nil {
			return err
		}
	}
	return nil
}

func convertMachineSpecToContractVersionedObjectReference(src *MachineSpec, dst *clusterv1.MachineSpec) error {
	infraRef, err := convertToContractVersionedObjectReference(&src.InfrastructureRef)
	if err != nil {
		return err
	}
	dst.InfrastructureRef = infraRef

	if src.Bootstrap.ConfigRef != nil {
		bootstrapRef, err := convertToContractVersionedObjectReference(src.Bootstrap.ConfigRef)
		if err != nil {
			return err
		}
		dst.Bootstrap.ConfigRef = bootstrapRef
	}

	return nil
}

func convertMachineSpecToObjectReference(src *clusterv1.MachineSpec, dst *MachineSpec, namespace string) error {
	if src.InfrastructureRef.IsDefined() {
		infraRef, err := convertToObjectReference(src.InfrastructureRef, namespace)
		if err != nil {
			return err
		}
		dst.InfrastructureRef = *infraRef
	}

	if src.Bootstrap.ConfigRef.IsDefined() {
		bootstrapRef, err := convertToObjectReference(src.Bootstrap.ConfigRef, namespace)
		if err != nil {
			return err
		}
		dst.Bootstrap.ConfigRef = bootstrapRef
	}

	return nil
}

func convertToContractVersionedObjectReference(ref *corev1.ObjectReference) (clusterv1.ContractVersionedObjectReference, error) {
	var apiGroup string
	if ref.APIVersion != "" {
		gv, err := schema.ParseGroupVersion(ref.APIVersion)
		if err != nil {
			return clusterv1.ContractVersionedObjectReference{}, fmt.Errorf("failed to convert object: failed to parse apiVersion: %v", err)
		}
		apiGroup = gv.Group
	}
	return clusterv1.ContractVersionedObjectReference{
		APIGroup: apiGroup,
		Kind:     ref.Kind,
		Name:     ref.Name,
	}, nil
}

func convertToObjectReference(ref clusterv1.ContractVersionedObjectReference, namespace string) (*corev1.ObjectReference, error) {
	apiVersion, err := apiVersionGetter(schema.GroupKind{
		Group: ref.APIGroup,
		Kind:  ref.Kind,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to convert object: %v", err)
	}
	return &corev1.ObjectReference{
		APIVersion: apiVersion,
		Kind:       ref.Kind,
		Namespace:  namespace,
		Name:       ref.Name,
	}, nil
}

func dropEmptyStringsMachineSpec(spec *MachineSpec) {
	dropEmptyString(&spec.Version)
	dropEmptyString(&spec.ProviderID)
	dropEmptyString(&spec.FailureDomain)
}

func dropEmptyString(s **string) {
	if *s != nil && **s == "" {
		*s = nil
	}
}
